Imports Cdm.DataCore.Entities
Imports Cdm.DataCore.Custom
Imports System.Collections.Generic
Imports Cdm.DataCore.Admin
Imports System.IO

Partial Class DataLoad_Upload
    Inherits System.Web.UI.Page

    Private Const C_REP_TABLE_ID = 14032
    Private Const C_LG_TABLE_ID = 14031
    Private Const C_PARTICIPANT_TABLE_ID = 14020
    Private Const C_PROGRAMINFO_TABLE_ID = 14038
    Dim dataLoadFields As List(Of AdminDataLoadFieldList)
    Dim SpecialFieldColumnHash As Hashtable

    Private Property DataLoadList() As List(Of ParticipantDataLoad)
        Get
            Return Session("ParticipantDataLoad")
        End Get
        Set(ByVal value As List(Of ParticipantDataLoad))
            Session("ParticipantDataLoad") = value
        End Set
    End Property

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        SetupJavascript()
        Me.ConfirmSuccessLabel.Visible = False
        Me.ConfirmSuccessLabel.Text = "File(s) have been saved."
        Me.SaveButton.Enabled = True

        If Not Me.IsPostBack Then
            If Not Request("reload") Is Nothing Then
                BindGrids()
                SetGridViewVisible(True)
            End If
        End If
    End Sub

    Private Sub SetupJavaScript()
        EntityController.JavaScriptSetFixedHeight(55)
    End Sub

    Private Sub BindGrids()
        Dim participants As List(Of ParticipantDataLoad) = ParticipantDataLoad.ListActiveByUserId(UserAuthorization.CurrentUser.UserId)
        Dim firstSpecialFieldColumn As Integer
        BuildDetailsGrid()
        firstSpecialFieldColumn = ParticipantDetailsScrollingGridView.Columns.Count

        Me.ParticipantDetailsScrollingGridView.DataSource = participants
        Me.ParticipantNameScrollingGridView.DataSource = participants
        Me.DataLoadList = participants
        AddSpecialFieldColumns()
        Me.ParticipantNameScrollingGridView.DataBind()
        Me.ParticipantDetailsScrollingGridView.DataBind()
        AddSpecialFieldValues(firstSpecialFieldColumn)
        SetDetailColumnWidths()

    End Sub

    Private Sub SetDetailColumnWidths()
        Dim maxLength As Integer
        Dim currentLength As Integer
        For iCol As Integer = 0 To Me.ParticipantDetailsScrollingGridView.Columns.Count - 1
            maxLength = 8 * ParticipantDetailsScrollingGridView.Columns(iCol).HeaderText.Length

            For iRow As Integer = 0 To Me.ParticipantDetailsScrollingGridView.Rows.Count - 1
                currentLength = ParticipantDetailsScrollingGridView.Rows(iRow).Cells(iCol).Text.Length * 6
                If currentLength > maxLength Then maxLength = currentLength
            Next

            Me.ParticipantDetailsScrollingGridView.Columns(iCol).ItemStyle.Width = CStr(maxLength)
            Me.ParticipantDetailsScrollingGridView.Columns(iCol).HeaderStyle.Width = CStr(maxLength)
        Next

        Dim lastCol As Integer = Me.ParticipantDetailsScrollingGridView.Columns.Count - 1
        Me.ParticipantDetailsScrollingGridView.Columns(lastCol).HeaderStyle.Width = _
        Me.ParticipantDetailsScrollingGridView.Columns(lastCol).ItemStyle.Width.Value + 40

    End Sub

    Private Sub AddSpecialFieldValues(ByVal firstSPColumn As Integer)
        Dim SpecialFieldValueHash As Hashtable = GetSpecialFieldValueHash()
        For iRow As Integer = 0 To ParticipantDetailsScrollingGridView.Rows.Count - 1
            Dim participantidString As String = ParticipantDetailsScrollingGridView.DataKeys(iRow)(0).ToString()
            For icol As Integer = firstSPColumn To ParticipantDetailsScrollingGridView.Columns.Count - 1
                Dim adminField As AdminDataLoadFieldList = SpecialFieldColumnHash.Item(ParticipantDetailsScrollingGridView.Columns(icol).HeaderText.Replace("(r)", "").TrimEnd())
                Dim tableidString As String = adminField.TableId.ToString()
                Dim fieldIdString As String = adminField.FieldId.ToString()

                Dim tableKeyString As String = GetTableKeyString(tableidString, iRow)
                Dim hashKey As String = String.Concat(fieldIdString, "||", tableKeyString, "||", tableidString)
                ParticipantDetailsScrollingGridView.Rows(iRow).Cells(icol).Text = DataLoadList(iRow).GetSpecialFieldValue(fieldIdString)
                'If SpecialFieldValueHash.ContainsKey(hashKey) Then
                'Dim spValue As SpecialFieldValue = CType(SpecialFieldValueHash.Item(hashKey), SpecialFieldValue)
                'ParticipantDetailsScrollingGridView.Rows(iRow).Cells(icol).Text = spValue.FieldValue
                'Else
                'ParticipantDetailsScrollingGridView.Rows(iRow).Cells(icol).Text = ""
                'End If

            Next
        Next
    End Sub

    Private Function GetTableKeyString(ByVal tableIdString As String, ByVal iRow As Integer) As String
        Dim iKey As Integer
        Select Case tableIdString
            Case C_LG_TABLE_ID
                iKey = 1
            Case C_REP_TABLE_ID
                iKey = 2
            Case Else
                iKey = 0
        End Select

        Return ParticipantDetailsScrollingGridView.DataKeys(iRow)(iKey).ToString()
    End Function

    Private Function GetSpecialFieldValueHash() As Hashtable
        Dim allvalues As IList(Of SpecialFieldValue) = SpecialFieldValue.ListAll()
        Dim valuesHash As New Hashtable
        For i As Integer = 0 To allvalues.Count - 1
            Dim valKey As String = String.Concat(allvalues(i).SpecialFieldId.ToString(), "||", allvalues(i).TableKey.ToString(), "||", allvalues(i).TableId.ToString())
            If Not valuesHash.ContainsKey(valKey) Then
                valuesHash.Add(valKey, allvalues(i))
            End If
        Next

        Return valuesHash

    End Function

    ''' <summary>
    ''' Adds the columns for the special field values and populates the values for each participant in 
    ''' the system.
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub AddSpecialFieldColumns()
        Dim tableName As String
        Dim fieldName As String
        Dim bHasUpdate As Boolean

        SpecialFieldColumnHash = New Hashtable()

        For iField As Integer = 0 To dataLoadFields.Count - 1
            tableName = dataLoadFields(iField).TableName
            fieldName = dataLoadFields(iField).FieldName


            If dataLoadFields(iField).IsSpecialField = True Then
                Dim newCol As New BoundField
                Dim tablePrefix As String
                Dim readOnlyChar As String = ""
                tablePrefix = GetTablePrefix(dataLoadFields(iField).TableId)
                SpecialFieldColumnHash.Add(tablePrefix & dataLoadFields(iField).FieldDisplayName, dataLoadFields(iField))
                bHasUpdate = UserHasSpecialFieldPermission(dataLoadFields(iField).TableId)
                If bHasUpdate = False Then readOnlyChar = "(r)"
                newCol.HeaderText = String.Concat(tablePrefix, dataLoadFields(iField).FieldDisplayName, " ", readOnlyChar)
                ParticipantDetailsScrollingGridView.Columns.Add(newCol)
            End If
        Next
    End Sub

    Private Function UserHasSpecialFieldPermission(ByVal tableid As Integer) As Boolean
        Select Case tableid
            Case C_LG_TABLE_ID
                Return UserAuthorization.HasUpdatePermission(Cdm.DataCore.UserSecurity.Permission.PermissionType.CaseLegalGuardian)
            Case C_REP_TABLE_ID
                Return UserAuthorization.HasUpdatePermission(Cdm.DataCore.UserSecurity.Permission.PermissionType.CaseParticipantRep)
            Case Else
                Return UserAuthorization.HasUpdatePermission(Cdm.DataCore.UserSecurity.Permission.PermissionType.CasePersonal)
        End Select
    End Function

    Private Function GetTablePrefix(ByVal tableId As Integer) As String
        Select Case tableId
            Case C_LG_TABLE_ID
                Return "Guardian "
            Case C_REP_TABLE_ID
                Return "Rep "
            Case Else
                Return ""
        End Select
    End Function

    ''' <summary>
    ''' Returns the input text, suitable for csv.
    ''' Rules:  1) Sometimes the text in the grid is a space, except html encoded <PRE>(nbsp;)</PRE>
    '''         This needs to be HTMLDecoded.
    '''         2) Trim the overall value
    '''         3) place all values in quotes, to handle the case where a value has a comma within it.
    '''         4) If a value has a quote within it double the quote so the file knows not
    '''            to end the cell at the first quote.
    '''         
    ''' </summary>
    ''' <param name="inputText">string with the value to clean</param>
    ''' <returns>string - cleaned version of the input string</returns>
    ''' <remarks></remarks>
    Private Function RemoveQuotes(ByVal inputText As String) As String
        Dim C_QUOTE As Char = Chr(34)
        Dim C_DBL_QUOTE As Char = Chr(34) & Chr(34)
        Dim C_TICK As Char = "'"

        Dim unQuotedText As String = inputText
        While unQuotedText.StartsWith("""")
            unQuotedText = unQuotedText.Substring(1)
        End While
        While (unQuotedText.EndsWith(""""))
            unQuotedText = unQuotedText.Substring(0, Len(unQuotedText) - 1)
        End While


        Return unQuotedText.Replace(C_DBL_QUOTE, C_QUOTE)

    End Function

    Private Sub BuildDetailsGrid()
        Dim bHasUpdate As Boolean
        Dim tableName As String
        Dim fieldName As String

        ParticipantDetailsScrollingGridView.Columns.Clear()
        dataLoadFields = AdminDataLoadFieldList.ListAll()
        For iField As Integer = 0 To dataLoadFields.Count - 1
            tableName = dataLoadFields(iField).TableName
            fieldName = dataLoadFields(iField).FieldName
            Dim bIncludeInDetails As Boolean = True
            bHasUpdate = UserAuthorization.CurrentUser.HasFormLevelPermission(tableName, fieldName)

            If tableName = "Participant" Then
                Select Case fieldName
                    Case "FirstName", "LastName", "ParticipantId"
                        bIncludeInDetails = False
                    Case Else
                        bIncludeInDetails = True
                End Select
            End If

            If dataLoadFields(iField).IsSpecialField = False And bIncludeInDetails Then
                Dim newCol As New BoundField
                newCol.DataField = ParticipantDataLoad.GetFieldIdPropertyName(dataLoadFields(iField).FieldId)
                Dim tablePrefix As String
                Dim readOnlyChar As String = ""

                tablePrefix = GetTablePrefix(dataLoadFields(iField).TableId)
                If bHasUpdate = False Then readOnlyChar = "(r)"
                newCol.HeaderText = String.Concat(tablePrefix, dataLoadFields(iField).FieldDisplayName, " ", readOnlyChar)
                ParticipantDetailsScrollingGridView.Columns.Add(newCol)
            End If
        Next


        Dim scrollScript As String
        scrollScript = String.Format("alignDivs('{0}', '{1}', '{2}');", _
                                   ParticipantDetailsScrollingGridView.DivClientId, _
                                   ParticipantNameScrollingGridView.DivClientId, _
                                   ParticipantDetailsScrollingGridView.HeaderDivClientId)
        ParticipantDetailsScrollingGridView.OnScrollJavaScript = scrollScript

    End Sub

    Protected Sub UploadButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles UploadButton.Click
        Dim participantDataLoadList As New System.Collections.Generic.List(Of ParticipantDataLoad)
        Dim sHeaderLine As String

        If UploadFile.PostedFile Is Nothing Then Exit Sub
        If UploadFile.PostedFile.FileName.Equals("") Then
            Exit Sub
            'participantDataLoadList = Me.DataLoadList
        Else
            Dim inputStream As System.IO.StreamReader = New StreamReader(UploadFile.PostedFile.InputStream)
            sHeaderLine = inputStream.ReadLine()
            While Not inputStream.EndOfStream
                Dim sLine As String = inputStream.ReadLine()
                Dim newPDL As ParticipantDataLoad = GetInputDataLoadLine(sLine)
                If Not newPDL Is Nothing Then
                    participantDataLoadList.Add(newPDL)
                End If
            End While
            inputStream.Close()
        End If



        Me.ParticipantNameScrollingGridView.DataSource = participantDataLoadList
        Me.ParticipantNameScrollingGridView.DataBind()
        BuildDetailsGrid()
        Dim firstSpecialFieldColumn As Integer
        firstSpecialFieldColumn = ParticipantDetailsScrollingGridView.Columns.Count

        AddSpecialFieldColumns()
        CheckHeadersInUploadFile(sHeaderLine)
        Me.ParticipantDetailsScrollingGridView.DataSource = participantDataLoadList
        Me.ParticipantDetailsScrollingGridView.DataBind()
        Me.DataLoadList = participantDataLoadList


        AddSpecialFieldValues(firstSpecialFieldColumn)
        SetGridViewVisible(True)
        SetDetailColumnWidths()

    End Sub

    Private Sub CheckHeadersInUploadFile(ByVal sHeaderLine As String)
        Dim headers() As String = sHeaderLine.Split(",")
        For iCol As Integer = 3 To headers.Length - 1
            If Not headers(iCol).Equals(Me.ParticipantDetailsScrollingGridView.Columns(iCol - 3).HeaderText.Trim()) Then
                Me.ConfirmSuccessLabel.Text = String.Format("Format problem in file.  In column {0}, your file heading is {1}, but the expected heading is {2}. " & _
                                      "  It is recommended that you download another file.", _
                                         (iCol + 1).ToString(), headers(iCol), Me.ParticipantDetailsScrollingGridView.Columns(iCol - 3).HeaderText)
                Me.ConfirmSuccessLabel.Visible = True
                Me.SaveButton.Enabled = False

            End If
        Next
    End Sub

    Private Sub SetGridViewVisible(ByVal isVisible As Boolean)
        Me.PagePanel.Visible = isVisible
        Me.SaveButton.Visible = isVisible
        Me.UploadFilePanel.Visible = Not isVisible
        Me.ShowFileLinkButton.Visible = isVisible
    End Sub


    Private Function GetInputDataLoadLine(ByVal sLine As String) As ParticipantDataLoad
        Dim pdl As New ParticipantDataLoad
        Dim lineArray() As String = sLine.Split(",")
        Dim iPrimary As Integer
        Try

            pdl.ParticipantId = lineArray(0).Replace(Chr(34), "")
            pdl.FirstName = RemoveQuotes(lineArray(1))
            pdl.LastName = RemoveQuotes(lineArray(2))

            Dim lastColumn As Integer = AdminDataLoadFieldList.PrimaryFields.Count - 1

            For iPrimary = 0 To lastColumn
                Try
                    Dim fieldId As Integer = AdminDataLoadFieldList.PrimaryFields(iPrimary).FieldId
                    Dim fieldValue As String = RemoveQuotes(lineArray(iPrimary + 3))
                    pdl.SetPropertyValueByFieldId(fieldId, fieldValue)
                Catch
                    Dim adl As AdminDataLoadFieldList = AdminDataLoadFieldList.PrimaryFields(iPrimary)
                    Response.Write(String.Concat(adl.FieldId.ToString(), ":", adl.FieldName.ToString()))
                End Try
            Next
            'Response.End()

            pdl.ClearSpecialFieldValues()
            For iSpecial As Integer = 0 To AdminDataLoadFieldList.SpecialFields.Count - 1
                Dim fieldName As String = AdminDataLoadFieldList.SpecialFields(iSpecial).FieldName
                Dim fieldId As Integer = AdminDataLoadFieldList.SpecialFields(iSpecial).FieldId
                Dim tableId As Integer = AdminDataLoadFieldList.SpecialFields(iSpecial).TableId
                Dim fieldValue As String = RemoveQuotes(lineArray(lastColumn + iSpecial + 3 + 1))
                pdl.SetSpecialFieldValue(fieldName, fieldValue, fieldId, tableId)
            Next
            Return pdl
        Catch ex As Exception
            Return Nothing
        End Try

    End Function

    Private Function FieldPrefix(ByVal tableId As Integer) As String
        Select Case tableId
            Case C_LG_TABLE_ID
                Return "Lg"
            Case C_REP_TABLE_ID
                Return "Rep"
            Case Else
                Return ""
        End Select
    End Function

    Protected Sub SaveButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SaveButton.Click

        Dim saveParticipant As Participant
        Dim saveParticipantList As New List(Of Participant) 'List of Participants to Save
        Dim errorParticipantList As New List(Of Participant) ' List of Participants with save validation errors
        Dim saveLegalGuardian As LegalGuardian
        Dim saveRepresentative As ParticipantRepresentative

        Dim dataLoadParticipants As List(Of ParticipantDataLoad) = Me.DataLoadList
        Dim currentDataLoadParticipant As ParticipantDataLoad
        Dim iPrimary As Integer
        Dim bErrorsSaving As Boolean = False

        Dim checkFieldMessage As String = CheckFieldMatchError(AdminDataLoadFieldList.PrimaryFields, AdminDataLoadFieldList.SpecialFields)
        If Not String.IsNullOrEmpty(checkFieldMessage) Then
            Me.ConfirmSuccessLabel.Text = "The format of your file does not match the expected input format.  The description is as follows: " + checkFieldMessage + _
                                            "It is recommended that you download another file and use that for your upload."
            Me.ConfirmSuccessLabel.Visible = True
            Exit Sub
        End If

        For iRow As Integer = 0 To dataLoadParticipants.Count - 1
            currentDataLoadParticipant = dataLoadParticipants(iRow)
            Dim participantId As Integer = dataLoadParticipants(iRow).ParticipantId
            Dim legalGuardianId As Integer = dataLoadParticipants(iRow).LegalGuardianId
            Dim representativeId As Integer = dataLoadParticipants(iRow).ParticipantRepresentativeId
            Dim hasRep As Boolean = False, hasGuardian As Boolean = False

            Dim uploadCheckBox As CheckBox = ParticipantNameScrollingGridView.Rows(iRow).FindControl("uploadCheckBox")

            If uploadCheckBox.Checked Then
                If participantId > 0 Then
                    saveParticipant = Participant.Retrieve(participantId)
                Else
                    saveParticipant = New Participant()
                End If

                saveParticipant.SetSpecialFieldListItemValidation(True)
                saveParticipant.FirstName = currentDataLoadParticipant.FirstName
                saveParticipant.LastName = currentDataLoadParticipant.LastName

                saveRepresentative = saveParticipant.Representative
                If representativeId > 0 Then
                    hasRep = True
                Else
                    If Not String.IsNullOrEmpty(dataLoadParticipants(iRow).RepLastName) Then
                        hasRep = True
                    Else
                        hasRep = False
                    End If
                End If

                saveLegalGuardian = saveParticipant.Guardian
                If legalGuardianId > 0 Then
                    hasGuardian = True
                Else
                    If Not String.IsNullOrEmpty(dataLoadParticipants(iRow).LgLastName) Then
                        hasGuardian = True
                    Else
                        hasGuardian = False
                    End If
                End If


                'Set the Primary Fields values
                For iPrimary = 0 To AdminDataLoadFieldList.PrimaryFields.Count - 1
                    Dim currField As AdminDataLoadFieldList = AdminDataLoadFieldList.PrimaryFields(iPrimary)
                    Dim bMayUpdate As Boolean = UserAuthorization.CurrentUser.HasFormLevelPermission(currField.TableName, currField.FieldName)
                    'Skip the updates if the current field is not editable by the 
                    'current user
                    If bMayUpdate Then
                        If currField.TableId = C_REP_TABLE_ID And hasRep = True Then
                            saveRepresentative.SetDataLoadProperty(currField.FieldName, dataLoadParticipants(iRow).GetPropertyValue(currField.FieldId), currField.FieldDisplayName, "Participant Representative")
                        ElseIf currField.TableId = C_LG_TABLE_ID And hasGuardian = True Then
                            saveLegalGuardian.SetDataLoadProperty(currField.FieldName, dataLoadParticipants(iRow).GetPropertyValue(currField.FieldId), currField.FieldDisplayName, "Legal Guardian")
                        ElseIf currField.TableId <> C_REP_TABLE_ID And _
                               currField.TableId <> C_LG_TABLE_ID Then
                            Dim sectionName As String = currField.TableName
                            saveParticipant.SetDataLoadProperty(currField.FieldName, dataLoadParticipants(iRow).GetPropertyValue(currField.FieldId), currField.FieldDisplayName, sectionName)
                        End If
                    End If
                Next


                'Set the Special Fields values
                For iSpecial As Integer = 0 To currentDataLoadParticipant.SpecialFields.Count - 1
                    Dim currField As ParticipantDataLoad.SpecialFieldDataLoadValue = currentDataLoadParticipant.SpecialFields(iSpecial)

                    If currField.TableId = C_PARTICIPANT_TABLE_ID Then
                        saveParticipant.SetSpecialField(currField.FieldName, currField.FieldValue)
                    ElseIf currField.TableId = C_REP_TABLE_ID And hasRep = True Then
                        saveRepresentative.SetSpecialField(currField.FieldName, currField.FieldValue)
                    ElseIf currField.TableId = C_LG_TABLE_ID And hasGuardian = True Then
                        saveLegalGuardian.SetSpecialField(currField.FieldName, currField.FieldValue)
                    End If

                Next

                saveParticipant.HasLegalGuardian = hasGuardian
                saveParticipant.HasRepresentative = hasRep
                saveParticipant.Validate()

                If saveParticipant.HasErrors Then
                    bErrorsSaving = True
                    errorParticipantList.Add(saveParticipant)
                End If

                saveParticipantList.Add(saveParticipant)
            End If
        Next

        If bErrorsSaving Then
            Session("DataLoadErrorList") = errorParticipantList
            Response.Redirect("UploadErrors.aspx")
        Else
            Dim trans As New Gentle.Framework.Transaction()
            Dim i As Integer
            Try
                For i = 0 To saveParticipantList.Count - 1
                    saveParticipantList(i).Persist(trans)
                Next
                trans.Commit()
                Me.ConfirmSuccessLabel.Visible = True
            Catch ex As Exception
                trans.Rollback()
            End Try

        End If

    End Sub

    Private Function CheckFieldMatchError(ByVal primaryFields As List(Of AdminDataLoadFieldList), ByVal specialFields As List(Of AdminDataLoadFieldList)) As String
        Dim dbFieldDisplayName As String
        Dim fileFieldDisplayName As String
        Dim tableName As String
        Dim iColumnNumber As Integer = -1
        Dim bIncludeInDetails As Boolean = False
        For iPrimary As Integer = 0 To primaryFields.Count - 1
            dbFieldDisplayName = String.Concat(GetTablePrefix(primaryFields(iPrimary).TableId), _
                                                             primaryFields(iPrimary).FieldDisplayName).Trim()
            tableName = primaryFields(iPrimary).TableName
            If tableName = "Participant" Then
                Select Case primaryFields(iPrimary).FieldName
                    Case "FirstName", "LastName", "ParticipantId"
                        bIncludeInDetails = False
                    Case Else
                        bIncludeInDetails = True
                End Select
            End If

            If bIncludeInDetails Then
                iColumnNumber = iColumnNumber + 1
                fileFieldDisplayName = Me.ParticipantDetailsScrollingGridView.Columns(iColumnNumber).HeaderText.Trim()
                If fileFieldDisplayName.EndsWith("(r)") Then
                    fileFieldDisplayName = fileFieldDisplayName.Substring(0, fileFieldDisplayName.Length - 3).Trim()
                End If
                If Not fileFieldDisplayName.Equals(dbFieldDisplayName) Then
                    Return String.Format("Column {0} is '{1}' in your file, where '{2}' was expected.", _
                               iColumnNumber.ToString(), fileFieldDisplayName, dbFieldDisplayName)
                End If

            End If


        Next

        Return ""
    End Function

    Protected Sub ShowFileLinkButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ShowFileLinkButton.Click
        SetGridViewVisible(False)
    End Sub
End Class
